from collections.abc import MutableMapping
from typing import Any, Iterable, Mapping

NO_DEFAULT = object()


def get_entry_or_attribute(obj: dict | object, name: str | Iterable[str], default: Any = NO_DEFAULT) -> Any | None:
    if not isinstance(name, str):
        names = tuple(name)
        if len(names) == 0:
            return obj
        if len(names) == 1:
            return get_entry_or_attribute(obj, names[0], default)
        obj = get_entry_or_attribute(obj, names[0])
        return get_entry_or_attribute(obj, names[1:], default)

    if isinstance(obj, Mapping):
        try:
            return obj.get(name)
        except KeyError:
            if default is NO_DEFAULT:
                raise
    else:
        try:
            return getattr(obj, name)
        except AttributeError:
            if default is NO_DEFAULT:
                raise
    return default


def set_entry_or_attribute(obj: Any, name: str | Iterable[str], value: Any):
    if not isinstance(name, str):
        names = tuple(name)
        if len(names) == 0:
            raise TypeError("Expected at least one attribute/key name!")
        if len(names) == 1:
            set_entry_or_attribute(obj, names[0], value)
            return
        sub = {}
        set_entry_or_attribute(sub, names[1:], value)
        set_entry_or_attribute(obj, names[0], sub)
        return

    if isinstance(obj, MutableMapping):
        obj[name] = value
    else:
        setattr(obj, name, value)
